
#pragma once
#include <iostream>

#include "online.hpp"

typedef enum
{
    UNLOGIN,
    LOGIN
} ss_statu;

class session
{
private:
    uint64_t _ssid;                  // 标识符
    uint64_t _uid;                   // session对应的用户ID
    ss_statu _statu;                 // 用户状态；未登录，已登录
    websocket_server::timer_ptr _tp; // session关联的定时器

public:
    session(uint64_t ssid) : _ssid(ssid)
    {
        LOG_INF("session %p 被创建", this);
    }

    ~session()
    {
        LOG_INF("session %p 被释放", this);
    }

    uint64_t ssid() { return _ssid; }

    void set_statu(ss_statu statu) { _statu = statu; }

    uint64_t get_uid() { return _uid; }

    void set_uid(uint64_t uid) { _uid = uid; }

    bool is_login() { return (_statu == LOGIN); }

    void set_timer(const websocket_server::timer_ptr &tp) { _tp = tp; }

    websocket_server::timer_ptr &get_timer() { return _tp; }
};

#define SESSION_TIMEOUT 30000 // 设置相应的超时时间

#define SESSION_FOREVER -1

using session_ptr = std::shared_ptr<session>;

class session_manager
{

private:
    uint64_t _next_ssid; // 相应的session标识
    std::mutex _mutex;
    std::unordered_map<uint64_t, session_ptr> _session;
    websocket_server *_server;

public:
    session_manager(websocket_server *srv) : _next_ssid(1), _server(srv)
    {
        LOG_INF("session管理器初始化完毕！");
    }

    ~session_manager()
    {
        LOG_INF("session管理器即将销毁.....");
    }

    // 创建相应的session，并加入管理队列
    session_ptr create_session(uint64_t uid, ss_statu statu)
    {
        std::unique_lock<std::mutex> lock(_mutex);

        session_ptr ssp(new session(_next_ssid));
        ssp->set_statu(statu);
        ssp->set_uid(uid);
        _session.insert(std::make_pair(_next_ssid, ssp));
        _next_ssid++;
        return ssp;
    }

    // 将已有的连接加入管理队列
    void append_session(const session_ptr &ssp)
    {
        std::unique_lock<std::mutex> lock(_mutex);
        _session.insert(std::make_pair(ssp->ssid(), ssp));
    }

    session_ptr get_session_by_ssid(uint64_t ssid)
    {
        std::unique_lock<std::mutex> lock(_mutex);

        auto it = _session.find(ssid);

        if (it == _session.end())
        {
            return session_ptr();
        }

        return it->second;
    }

    void remove_session(uint64_t ssid)
    {
        std::unique_lock<std::mutex> lock(_mutex);
        _session.erase(ssid);
    }

    // 设置相应的定时器
    void set_session_expire_time(uint64_t ssid, int ms)
    {
        session_ptr ssp = get_session_by_ssid(ssid);

        if (ssp.get() == nullptr)
        {
            return;
        }

        websocket_server::timer_ptr tp = ssp->get_timer();

        // 没有关联定时器，代表这个是永久有效
        if (tp.get() == nullptr && ms == SESSION_FOREVER)
        {
            return;
        }
        else if (tp.get() == nullptr && ms != SESSION_FOREVER)
        {
            websocket_server::timer_ptr tmp_tp = _server->set_timer(ms, std::bind(&session_manager::remove_session, this, ssid));
            ssp->set_timer(tmp_tp);
        }
        else if (tp.get() != nullptr && ms == SESSION_FOREVER)
        {
            tp->cancel();
            ssp->set_timer(websocket_server::timer_ptr());

            _server->set_timer(0, std::bind(&session_manager::append_session, this, ssp));
        }
        else if (tp.get() != nullptr && ms != SESSION_FOREVER)
        {
            tp->cancel();
            ssp->set_timer(websocket_server::timer_ptr());
            _server->set_timer(0, std::bind(&session_manager::append_session, this, ssp));

            websocket_server::timer_ptr tmp_tp = _server->set_timer(ms, std::bind(&session_manager::remove_session, this, ssp->ssid()));

            ssp->set_timer(tmp_tp);
        }
    }
};